package org.xiaov.core.service;

import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.xiaov.common.bean.AutoCodeInfo;
import org.xiaov.common.bean.PropertyInfo;
import org.xiaov.common.bean.TemplateInfoExt;
import org.xiaov.common.constant.FreemarkerConstant;
import org.xiaov.common.exception.AutoCodeBizException;
import org.xiaov.common.util.MySqlToJavaUtil;
import org.xiaov.common.util.StringUtil;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 描述：自动生成代码工具类
 * </p>
 *
 * @author xiaovcloud
 * @since 2021/9/16 21:37
 */
@Slf4j
public class AutoCodeBiz {
    private static final String DEFAULT_AUTHOR = "auto-code-generation";

    /**
     * 创建文件
     *
     * @param autoCodeInfo 自动生成的基本信息
     * @param tableName    表名
     * @param cis          属性
     * @param packages     引入的包
     * @param primaryKey   主键
     */
    public static void createFile(AutoCodeInfo autoCodeInfo, String tableName, List<PropertyInfo> cis, Set<String> packages, String primaryKey) {
        //转换到模板数据中
        TemplateInfoExt templateInfo = castInfo(autoCodeInfo, tableName, cis, packages, primaryKey);
        String baseUrl = autoCodeInfo.getFileHost() + "\\" +
                autoCodeInfo.getPackPath().replace(".", "\\");

        //设置是否覆盖
        templateInfo.setFileOverride(autoCodeInfo.getFileOverride());

        createFile(templateInfo, baseUrl);

    }

    /**
     * 创建数据文件
     *
     * @param templateInfo 扩展模板
     * @param baseUrl      生成地址
     */
    private static void createFile(TemplateInfoExt templateInfo, String baseUrl) {
        //生成entity
        String entityUrl = getGeneratorFileUrl(baseUrl, templateInfo.getEntityName(), FreemarkerConstant.ENTITY);
        createFile(templateInfo, FreemarkerConstant.ENTITY_TEMPLATE_NAME, entityUrl);

        //生成mapper
        String mapperUrl = getGeneratorFileUrl(baseUrl, templateInfo.getEntityName(), FreemarkerConstant.MAPPER);
        createFile(templateInfo, FreemarkerConstant.MAPPER_TEMPLATE_NAME, mapperUrl);

        //生成xml
        String xmlUrl = getGeneratorFileUrl(baseUrl, templateInfo.getEntityName(), FreemarkerConstant.XML);
        createFile(templateInfo, FreemarkerConstant.MAPPER_XML_TEMPLATE_NAME, xmlUrl);

        //生成service
        String serviceUrl = getGeneratorFileUrl(baseUrl, templateInfo.getEntityName(), FreemarkerConstant.SERVICE);
        createFile(templateInfo, FreemarkerConstant.SERVICE_TEMPLATE_NAME, serviceUrl);

        //生成serviceImpl
        String serviceImplUrl = getGeneratorFileUrl(baseUrl, templateInfo.getEntityName(), FreemarkerConstant.SERVICE_IMPL);
        createFile(templateInfo, FreemarkerConstant.SERVICE_IMPL_TEMPLATE_NAME, serviceImplUrl);

        //生成controller
        String controllerUrl = getGeneratorFileUrl(baseUrl, templateInfo.getEntityName(), FreemarkerConstant.CONTROLLER);
        createFile(templateInfo, FreemarkerConstant.CONTROLLER_TEMPLATE_NAME, controllerUrl);
    }

    /**
     * 创建文件
     *
     * @param dataModel    模板数据
     * @param templateName 模板文件
     * @param filePath     生成文件地址
     */
    private static void createFile(TemplateInfoExt dataModel, String templateName, String filePath) {
        FileWriter out = null;
        try {
            // 通过FreeMarker的Configuration读取相应的模板文件
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
            // 设置模板路径
            configuration.setClassForTemplateLoading(AutoCodeBiz.class, "/freemarker");
            // 设置默认字体
            configuration.setDefaultEncoding("utf-8");
            // 获取模板
            Template template = configuration.getTemplate(templateName);

            File file = new File(filePath);
            if (!file.getParentFile().exists()) {
                boolean mkdirs = file.getParentFile().mkdirs();
                if (!mkdirs) {
                    throw new AutoCodeBizException("创建文件失败");
                }
            }
            boolean fileOverride = dataModel.getFileOverride() == null || dataModel.getFileOverride();
            if (file.exists() && fileOverride) {
                //存在,且覆盖文件
                boolean delete = file.delete();
                log.debug("删除文件[{}]成功", file.getName());
                boolean newFile = file.createNewFile();
            } else if (!file.exists()) {
                //文件不存在,直接生成
                boolean newFile = file.createNewFile();
            }

            //设置输出流
            out = new FileWriter(file);
            //模板输出静态文件
            template.process(dataModel, out);
            log.debug("创建文件[{}]成功", file.getName());
        } catch (Exception e) {
            e.printStackTrace();
            throw new AutoCodeBizException("创建文件失败: ", e);
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成文件路径和名字
     *
     * @param packageUrl 文件基础url
     * @param entityName 类名
     * @param type       文件的类型
     * @return .
     */
    private static String getGeneratorFileUrl(String packageUrl, String entityName, String type) {
        packageUrl = packageUrl.replace(".", "\\");
        if (FreemarkerConstant.ENTITY.equals(type)) {
            return packageUrl + "\\" + FreemarkerConstant.ENTITY + "\\" + entityName + ".java";
        } else if (FreemarkerConstant.DAO.equals(type)) {
            return packageUrl + "\\" + FreemarkerConstant.DAO + "\\" + entityName + "Dao.java";
        } else if (FreemarkerConstant.MAPPER.equals(type)) {
            return packageUrl + "\\" + FreemarkerConstant.MAPPER + "\\" + entityName + "Mapper.java";
        } else if (FreemarkerConstant.XML.equals(type)) {
            return packageUrl + "\\" + FreemarkerConstant.MAPPER + "\\" + FreemarkerConstant.XML + "\\" + entityName + "Mapper.xml";
        } else if (FreemarkerConstant.SERVICE.equals(type)) {
            return packageUrl + "\\" + FreemarkerConstant.SERVICE + "\\" + entityName + "Service.java";
        } else if (FreemarkerConstant.SERVICE_IMPL.equals(type)) {
            return packageUrl + "\\" + FreemarkerConstant.SERVICE + "\\impl\\" + entityName + "ServiceImpl.java";
        } else if (FreemarkerConstant.CONTROLLER.equals(type)) {
            return packageUrl + "\\" + FreemarkerConstant.CONTROLLER + "\\" + entityName + "Controller.java";
        }
        throw new AutoCodeBizException("不支持的文件类型:{}", type);
    }

    /**
     * 转换数据
     *
     * @param autoCodeInfo 自动生成代码的参数
     * @param tableName    表名
     * @param cis          列属性
     * @param pkgs         填充的基础包名
     * @param pk           主键
     * @return .
     */
    private static TemplateInfoExt castInfo(AutoCodeInfo autoCodeInfo, String tableName, List<PropertyInfo> cis,
                                            Set<String> pkgs, String pk) {
        String packPath = autoCodeInfo.getPackPath();
        String swagger = autoCodeInfo.isSwagger() ? "true" : "false";
        String date = StringUtil.date2String(new Date());
        String author = autoCodeInfo.getAuthor();
        if (StringUtil.isNullOrEmpty(author)) {
            author = DEFAULT_AUTHOR;
        }
        String entityName = MySqlToJavaUtil.getClassName(tableName, autoCodeInfo.getTablePrefix());

        String entityNameLow = MySqlToJavaUtil.lowFirstLetter(entityName);
        String containsPk = "true";
        if (StringUtil.isNullOrEmpty(pk)) {
            containsPk = "false";
        }
        String containsDate = "false";
        for (String packagePath : pkgs) {
            if ("java.sql.Date".equals(packagePath)) {
                containsDate = "true";
                break;
            }
        }
        return new TemplateInfoExt(packPath, swagger, pkgs, entityName, entityNameLow, tableName,
                date, author, cis, containsDate, pk, containsPk);
    }
}
